package com.xlongwei.todays.controller;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.noear.solon.Utils;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Post;
import org.noear.solon.core.handle.Result;
import org.noear.solon.core.util.RunUtil;
import org.noear.solon.validation.annotation.Min;
import org.noear.solon.validation.annotation.NotNull;
import org.noear.solon.validation.annotation.Pattern;
import org.noear.solon.validation.annotation.Valid;
import org.noear.solon.validation.annotation.Validated;
import com.xlongwei.todays.config.CronUtils;
import com.xlongwei.todays.dao.ExtraDao;
import com.xlongwei.todays.dao.MydoDao;
import com.xlongwei.todays.dao.TodoDao;
import com.xlongwei.todays.model.Extra;
import com.xlongwei.todays.model.Mydo;
import com.xlongwei.todays.model.Todo;
import com.xlongwei.todays.view.MydoQuery;
import com.xlongwei.todays.view.TodoQuery;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import lombok.extern.slf4j.Slf4j;

@Valid
@Slf4j
@Controller
@Mapping("todo")
@SaCheckLogin
public class TodoController {
    @Inject
    TodoDao todoDao;
    @Inject
    ExtraDao extraDao;
    @Inject
    MydoDao mydoDao;

    @Post
    @Mapping("create")
    @SaCheckRole(value = "admin")
    public Result<?> create(String cron, String title, @Pattern("[01]") String status,
            @Pattern("[01]") String next, String remark) {
        Todo row = new Todo();
        row.setCron(Utils.isBlank(cron) ? row.getCron() : cron);
        row.setTitle(title);
        row.setStatus(Utils.isBlank(status) ? row.getStatus() : status);
        row.setNext(Utils.isBlank(next) ? row.getNext() : next);
        if (!CronUtils.valid(row.getCron())) {
            return Result.failure("cron not valid");
        }
        Integer id = todoDao.create(row);
        Extra extra = new Extra();
        extra.setTodoid(id);
        extra.setRemark(remark);
        extraDao.create(extra);
        return Result.succeed(id);
    }

    @Post
    @Mapping("update")
    @SaCheckRole(value = "admin")
    public Result<?> update(@NotNull @Min(1) Integer todoid, String cron, String title,
            @Pattern("[01]") String status, @Pattern("[01]") String next, String remark) {
        Todo row = todoDao.retrieve(todoid);
        if (row != null) {
            row.setCron(Utils.isBlank(cron) ? row.getCron() : cron);
            row.setTitle(Utils.isBlank(title) ? row.getTitle() : title);
            row.setStatus(Utils.isBlank(status) ? row.getStatus() : status);
            row.setNext(Utils.isBlank(next) ? row.getNext() : next);
            if (!CronUtils.valid(row.getCron())) {
                return Result.failure("cron not valid");
            }
            todoDao.update(row);
            Extra extra = extraDao.retrieve(todoid);
            extra.setRemark(remark);
            extraDao.update(extra);
            row.setRemark(extra.getRemark());
        }
        return Result.succeed(row);
    }

    @Get
    @Post
    @Mapping("retrieve")
    public Result<?> retrieve(@NotNull @Min(1) Integer todoid) {
        Todo row = todoDao.retrieve(todoid);
        if (row != null) {
            Extra extra = extraDao.retrieve(todoid);
            row.setRemark(extra.getRemark());
        }
        return Result.succeed(row);
    }

    @Post
    @Mapping("list")
    public Result<?> list(@Validated TodoQuery query) {
        List<Todo> list = todoDao.list(query);
        if (list.size() > 0) {
            Integer userid = UserController.userid();
            MydoQuery mydoQuery = new MydoQuery();
            mydoQuery.setUserid(userid);
            List<Mydo> mydos = mydoDao.list(mydoQuery);
            for (Todo item : list) {
                Mydo mydo = mydos.stream().filter(e -> e.getTodoid() == item.getTodoid()).findAny().orElse(null);
                // Mydo mydo = mydoDao.findByUseridAndTodoid(userid, item.getTodoid());
                item.setMydo(mydo != null && !"0".equals(mydo.getStatus()));
            }
        }
        return Result.succeed(list);
    }

    @Init
    public void init() {
        Runnable run = () -> {
            mydos(null, null);
        };
        RunUtil.delay(run, 1000);
        // 明天开始，每天凌晨跑一次
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime target = now.plusDays(1).withHour(0).withMinute(0).withSecond(10).withNano(0);
        long millis = ChronoUnit.MILLIS.between(now, target);
        RunUtil.scheduleAtFixedRate(run, millis, TimeUnit.DAYS.toMillis(1));
    }

    @Get
    @Post
    @Mapping("mydos")
    @SaCheckRole(value = "admin")
    public Result<?> mydos(@Min(1) Integer userid, LocalDate today) {
        today = today == null ? LocalDate.now() : today;
        MydoQuery query = new MydoQuery();
        query.setUserid(userid);
        List<Mydo> list = mydoDao.list(query);
        for (Mydo row : list) {
            mydo(row, today);
        }
        return Result.succeed(list.size());
    }

    public void mydo(Mydo row, LocalDate today) {
        if (row == null || "0".equals(row.getStatus())) {
            return;// 我的待办：停用
        }
        TodoQuery query = new TodoQuery();
        query.setLimit(null);
        List<Todo> list = todoDao.list(query);
        Todo todo = list.stream().filter(item -> item.getTodoid().equals(row.getTodoid())).findAny().orElse(null);
        // Todo todo = todoDao.retrieve(row.getTodoid());
        if (todo == null || "0".equals(todo.getStatus())) {
            return;// 公共待办：停用
        }
        boolean todayDone = today.equals(row.getToday()) && "2".equals(row.getStatus());
        if (todayDone) {
            return; // 当天已完成
        }
        ZonedDateTime start = CronUtils.next(todo.getCron(), today);
        boolean valid = today.equals(start.toLocalDate());// 当天待办
        boolean next = !valid && "1".equals(todo.getNext()) && "1".equals(row.getStatus());// 顺延待办
        boolean hasUpdate = !today.equals(row.getToday()) || !start.toLocalTime().equals(row.getStart())
                || !"1".equals(row.getStatus()); // 字段有更新
        if ((valid || next) && hasUpdate) {
            row.setToday(today);
            row.setStart(start.toLocalTime());
            row.setStatus("1");
            mydoDao.update(row);
            return;
        }
    }

    @Get
    @Post
    @Mapping("mydo")
    @SaCheckRole(value = "admin")
    public Result<?> mydo(@NotNull @Min(1) Integer mydoid, LocalDate today) {
        today = today == null ? LocalDate.now() : today;
        Mydo row = mydoDao.retrieve(mydoid);
        mydo(row, today);
        return Result.succeed(row);
    }
}
